package com.alibaba.citrus.cr.unified.inventory.functions.handler;

import com.alibaba.citrus.cr.unified.inventory.contants.FeaturesKey;
import com.alibaba.citrus.cr.unified.inventory.functions.factory.AllocateOrderEntityFactory;
import com.alibaba.citrus.cr.unified.inventory.model.AllocateOrderEntity;
import com.alibaba.citrus.cr.unified.inventory.model.AllocateOrderEntityBatchComposeRequest;
import com.alibaba.citrus.cr.unified.inventory.model.AllocateOrderEntityComposeRequest;
import com.alibaba.citrus.cr.unified.inventory.model.enums.ReceiveStatus;
import com.alibaba.citrus.cr.unified.inventory.model.enums.ShipStatus;
import com.alibaba.citrus.cr.unified.inventory.utils.CompareUtil;
import com.alibaba.cz.base.tool.FeatureUtil;
import com.alibaba.cz.base.tool.Nullable;
import com.alibaba.cz.base.tool.log.Log;
import com.alibaba.fastjson.JSON;
import com.epoch.app.crunifiedinventory.domain.allocateorder.model.AllocateOrder;
import com.epoch.app.crunifiedinventory.domain.allocateorderdetail.model.AllocateOrderDetail;
import com.epoch.app.crunifiedinventory.model.enums.AllocateOrderStatus;
import com.epoch.app.crunifiedinventory.sdo.enums.AllocateOrderShipTypeEnums;
import com.epoch.app.crunifiedinventory.sdo.enums.AllocateOrderTypeEnum;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.collections4.MapUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @description:
 * @author: yuhw
 * @date: 2024年01月22日 21:45
 **/
@Component("planAllocateOrderStatusHandler")
public class PlanAllocateOrderStatusHandler implements AllocateOrderStatusHandler{
    private static Log log = Log.getLogger(PlanAllocateOrderStatusHandler.class);

    @Resource
    private PlanAllocateOrderStatusCompute planAllocateOrderStatusCompute;
    @Resource
    private AllocateOrderEntityFactory allocateOrderEntityFactory;
    @Resource
    private Plan2FreightYardAllocateOrderStatusCompute plan2FreightYardAllocateOrderStatusCompute;

    @Override
    public String getType() {
        return AllocateOrderTypeEnum.PLAN.getType().toString();
    }

    @Override
    public void process(AllocateOrder allocateOrder,List<AllocateOrderDetail> detailList,boolean isFreightYardReceive) {
        //主单状态 由子单状态一起推进
        //子单状态该怎么表示主单状态
        List<AllocateOrderStatus> statusList = detailList.stream().map(AllocateOrderDetail::getStatus).map(AllocateOrderStatus::of).collect(Collectors.toList());
        AllocateOrderStatus mainStatus;
        if (isFreightYardReceive){
            mainStatus = plan2FreightYardAllocateOrderStatusCompute.computeMainStatus(statusList);
        }else {
            mainStatus = planAllocateOrderStatusCompute.computeMainStatus(statusList);
        }
        log.info("PlanAllocateOrderStatusHandler_computeMainStatus:{}",JSON.toJSONString(mainStatus));
        allocateOrder.setStatus(mainStatus.getValue());
    }

    @Override
    public void process(AllocateOrderDetail allocateOrderDetail, boolean isFreightYardReceive) {
        log.info("PlanAllocateOrderStatusHandler_request:{},isFreightYardReceive:{} ", JSON.toJSONString(allocateOrderDetail),isFreightYardReceive);
        String quantity = allocateOrderDetail.getQuantity();
        String bizFeatures = allocateOrderDetail.getBizFeatures();
        Map<String, String> bizFeaturesMap = FeatureUtil.fromString(bizFeatures);
        if (MapUtils.isEmpty(bizFeaturesMap)){
            return;
        }
        //特判一些状态不处理
        if (CompareUtil.anyOf(allocateOrderDetail.getStatus(),AllocateOrderStatus.Cancel.getValue())){
            log.info("PlanAllocateOrderStatusHandler_skip_status:{}",JSON.toJSONString(allocateOrderDetail));
            return;
        }

        //这里命名用ship?
        String deliveryQuantity = bizFeaturesMap.get(FeaturesKey.CUMULATIVE_DELIVERY_QUANTITY);
        String receiveQuantity = bizFeaturesMap.get(FeaturesKey.CUMULATIVE_RECEIVED_QUANTITY);

        if (Boolean.TRUE.equals(allocateOrderDetail.getClose())){
            if (CompareUtil.lessThanOrEqual(deliveryQuantity, BigDecimal.ZERO.toString()) &&
                    CompareUtil.lessThanOrEqual(receiveQuantity, BigDecimal.ZERO.toString())) {
                log.info("PlanAllocateOrderStatusHandler_skip_compute:{}",JSON.toJSONString(allocateOrderDetail));
                return;
            }
        }
        //数量比较
        //发货 未发, 部分发, 全发
        //收货 未收, 部分收, 全收
        ShipStatus shipStatus = computeShipStatus(deliveryQuantity, quantity,allocateOrderDetail.getClose());
        log.info("computeShipStatus:{}",JSON.toJSONString(shipStatus));
        ReceiveStatus receiveStatus = computeReceiveStatus(receiveQuantity, quantity,allocateOrderDetail.getClose());
        log.info("computeReceiveStatus:{}",JSON.toJSONString(receiveStatus));

        //收发状态合起来比较, TODO 这里的状态是否会有关闭/取消的影响
        AllocateOrderStatus allocateOrderStatus;
        if (isFreightYardReceive){
            allocateOrderStatus = plan2FreightYardAllocateOrderStatusCompute.computeStatus(shipStatus,receiveStatus);
        }else {
            allocateOrderStatus = planAllocateOrderStatusCompute.computeStatus(shipStatus, receiveStatus);
        }
        if (allocateOrderStatus != null){
            allocateOrderDetail.setStatus(allocateOrderStatus.getValue());
        }
    }

    /**
     * 先直接由该处理方法push吧
     */
    public boolean freightYardPickedUpPushStatus(AllocateOrderEntity allocateOrderEntity){
//        查询货场提货单到对应的调拨单
//        String relatedAllocateOrderCode = allocateOrderEntity.getAllocateOrder().getRelatedAllocateOrderCode();
//        /**
//         * 获取到计划调拨2货场仓的
//         * 查出对应的所有的货场提货单及明细
//         * 计算计划货场的每行明细状态,再推进主单状态
//         *
//         */
//        AllocateOrderEntityComposeRequest composeRequest = AllocateOrderEntityComposeRequest.builder()
//                        .code(relatedAllocateOrderCode).build();
//        AllocateOrderEntity planOrderEntity = allocateOrderEntityFactory.composeAllocateOrderEntity(composeRequest);
//        if (planOrderEntity == null){
//            log.error("freightYardReceive_plan_order_empty:{}",relatedAllocateOrderCode);
//            return;
//        }
        //查询该F-F1货场下的所有货场提货单
        String relatedAllocateOrderCode = allocateOrderEntity.getAllocateOrder().getCode();
        AllocateOrderEntityBatchComposeRequest batchComposeRequest = AllocateOrderEntityBatchComposeRequest.builder()
                .relatedAllocateOrderCode(relatedAllocateOrderCode).build();
        List<AllocateOrderEntity> entityList = allocateOrderEntityFactory.batchComposeAllocateOrderEntityList(batchComposeRequest);
        if (CollectionUtils.isEmpty(entityList)){
            log.error("freightYardReceive_no_data");
            return false;
        }
        /**
         * 所有货场仓明细按行号进行分组 行号原因 这里需要取
         */
        Map<String, List<AllocateOrderDetail>> lineMap = entityList.stream().flatMap(entity -> entity.getDetailList().stream())
                .filter(x -> StringUtils.isNotBlank(x.getRelatedAllocateSubOrderId()))
                .collect(Collectors.groupingBy(AllocateOrderDetail::getRelatedAllocateSubOrderId));
        for (AllocateOrderDetail planDetail : allocateOrderEntity.getDetailList()) {
            List<AllocateOrderDetail> detailList = lineMap.get(String.valueOf(planDetail.getLineNo()));
            //不考虑closed的情况
            if (CollectionUtils.isNotEmpty(detailList)){
                List<AllocateOrderStatus> detailStatusList = detailList.stream().map(AllocateOrderDetail::getStatus)
                        .map(AllocateOrderStatus::of).collect(Collectors.toList());
                log.info("PlanAllocateOrderStatusHandler_computeLineMainStatusList_req:{},lineNo:{}",JSON.toJSONString(detailStatusList),JSON.toJSONString(planDetail.getLineNo()));
                AllocateOrderStatus lineMainStatus = plan2FreightYardAllocateOrderStatusCompute.computeLineMainStatusList(detailStatusList);
                log.info("PlanAllocateOrderStatusHandler_computeLineMainStatusList_res:{},lineNo:{}",JSON.toJSONString(lineMainStatus),JSON.toJSONString(planDetail.getLineNo()));
                if (lineMainStatus != null){
                    //TODO 简单判断下计划调拨单数量 和 货场提货单的数量
                    if (lineMainStatus == AllocateOrderStatus.COMPLETED){
                        //这里是因为, 关联单可能有没提货的数量
                        BigDecimal freightYardSumQuantity = detailList.stream().map(AllocateOrderDetail::getQuantity).map(String::trim).map(BigDecimal::new).reduce(BigDecimal.ZERO, BigDecimal::add);
                        if (freightYardSumQuantity.compareTo(new BigDecimal(planDetail.getQuantity().trim())) < 0){
                            planDetail.setStatus(AllocateOrderStatus.ALL_SHIPPED_PART_FINAL_RECEIVED.getValue());
                        }else {
                            planDetail.setStatus(AllocateOrderStatus.COMPLETED.getValue());
                        }
                    }else {
                        planDetail.setStatus(lineMainStatus.getValue());
                    }
                }
            }
        }
        //计算主单状态
        List<AllocateOrderStatus> lineStatusList = allocateOrderEntity.getDetailList().stream().map(AllocateOrderDetail::getStatus).map(AllocateOrderStatus::of).collect(Collectors.toList());
        log.info("PlanAllocateOrderStatusHandler_computePlanOrderFreightYardMainStatus_req:{}",JSON.toJSONString(lineStatusList));
        AllocateOrderStatus mainStatus = plan2FreightYardAllocateOrderStatusCompute.computePlanOrderFreightYardMainStatus(lineStatusList);
        log.info("PlanAllocateOrderStatusHandler_computePlanOrderFreightYardMainStatus_res:{}",JSON.toJSONString(mainStatus));
        //TODO 计算状态时 如果报错了怎么办
        if (mainStatus != null){
            allocateOrderEntity.getAllocateOrder().setStatus(mainStatus.getValue());
        }
        return true;
    }

    private ShipStatus computeShipStatus(String deliveryQuantity, String quantity,Boolean isClose){
        boolean greaterThan = CompareUtil.greaterThan(deliveryQuantity, BigDecimal.ZERO.toString());
        boolean lessThan = CompareUtil.lessThan(deliveryQuantity, quantity);
        if (greaterThan){
            //如果有关闭标记,特判全部出库
            if (Boolean.TRUE.equals(isClose)){
                return ShipStatus.ALL;
            }

            if (lessThan){
                return ShipStatus.PART;
            }else {
                return ShipStatus.ALL;
            }
        }
        return ShipStatus.NONE;
    }

    private ReceiveStatus computeReceiveStatus(String receiveQuantity, String quantity,Boolean isClose){
        boolean greaterThan = CompareUtil.greaterThan(receiveQuantity, BigDecimal.ZERO.toString());
        boolean lessThan = CompareUtil.lessThan(receiveQuantity, quantity);
        if (greaterThan){
            //如果有关闭状态,特判全部入库
            if (Boolean.TRUE.equals(isClose)){
                return ReceiveStatus.ALL;
            }
            if (lessThan){
                return ReceiveStatus.PART;
            }else {
                return ReceiveStatus.ALL;
            }
        }
        return ReceiveStatus.NONE;
    }

    /**
     * 计划调拨单场景下需要特殊判断下是否F-F1 运输方式是铁运/海运
     */
    @Override
    public boolean isFreightYardReceive(AllocateOrder allocateOrder) {
        return AllocateOrderShipTypeEnums.TRAIN.getType().equals(allocateOrder.getShipMethod()) ||
                AllocateOrderShipTypeEnums.SEA.getType().equals(allocateOrder.getShipMethod());
    }
}
